{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 截尾取整"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 简介"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "trunc 是一个抹掉数字小数位的功能函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python 中的 trunc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "8\n",
      "0\n",
      "-9\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "print(math.trunc(2.77))\n",
    "print(math.trunc(8.32))\n",
    "print(math.trunc(-0))\n",
    "print(math.trunc(-9.99))\n",
    "# print(math.trunc(math.inf)) error"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## JS 实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```javascript\n",
    "const trunc = (x) => {\n",
    "  return x >= 0 ? Math.floor(x) : Math.ceil(x)\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果这么写，和[高斯函数](https://math.haozi.me/floor.html)的实现造成循环引用了。这里有一些[奇技淫巧](https://github.com/akira-cn/FE_You_dont_know/issues/5)。但在工程上我不推荐，因为这样会让代码变得难读，语义不够明确。特别是用位运算取整，要注意溢出风险："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```javascript\n",
    "4294967296.1 | 0 // 0\n",
    "~~4294967296.1 // 0\n",
    "Math.trunc(4294967296.1) // 4294967296\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "模 1 不是奇技淫巧，我们可以用模运算实现一个符合 JS 规范的 trunc:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```javascript\n",
    "const trunc = (x) => {\n",
    "  x = +x\n",
    "  if (!isFinite(x)) return x\n",
    "  if (Object.is(x, -0)) return x\n",
    "  const dec = x % 1\n",
    "  const int = x - dec\n",
    "  if (x < 0 && int === 0) return -0\n",
    "  return int\n",
    "}\n",
    "\n",
    "//  0        ->  0\n",
    "// -0        -> -0\n",
    "//  0.2      ->  0\n",
    "// -0.2      -> -0\n",
    "//  0.7      ->  0\n",
    "// -0.7      -> -0\n",
    "//  Infinity ->  Infinity\n",
    "// -Infinity -> -Infinity\n",
    "//  NaN      ->  NaN\n",
    "//  null     ->  0\n",
    "//  2.7      ->  2\n",
    "// -2.3      -> -2\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "关于 Math.trunc 的相关话题，可以在[这里留言](https://github.com/haozi/Math/issues/14)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
